using System;
using System.Collections.Generic;
using Config;
using Cysharp.Threading.Tasks;
using Data;
using MoonFramework.Scripts.Tool;
using MoonFramework.Scripts.Tool.System.Setting;
using Tool;
using Tool.Name;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Map
{
    public class MapFactory
    {
        private static readonly int MainTex = Shader.PropertyToID("_MainTex");

        #region 运行时的逻辑
        private MapGrid _mapGrid; // 地图逻辑网格、顶点数据
        private Material _marshMaterial;
        private Mesh _blockMesh;
        private int _forestMapObjectWeightTotal;
        private int _marshMapObjectWeightTotal;
        private int _forestAIWeightTotal;
        private int _marshAIWeightTotal;
        private readonly Texture2D[] _mapTexture = new Texture2D[16];
        #endregion

        #region 配置相关
        private readonly Dictionary<MapVertexType, List<int>> _createMapObjectConfigs;
        private readonly Dictionary<MapVertexType, List<int>> _createAIConfigs;
        private readonly List<int> _marshMapObjects;
        private readonly List<int> _forestMapObjects;
        private readonly List<int> _marshAIObjects;
        private readonly List<int> _forestAIObjects;
        private readonly MapConfig _mapConfig;
        #endregion

        #region 存档
        private readonly MapInitData _mapInitData;
        private readonly MapData _mapData;
        #endregion
        
        public MapFactory(MapConfig mapConfig, MapInitData mapInitData,MapData mapData, Dictionary<MapVertexType, List<int>> createMapObjectConfigs, Dictionary<MapVertexType, List<int>> createAIConfigs)
        {
            _mapConfig = mapConfig;
            _mapInitData = mapInitData;
            _mapData = mapData;
            _createMapObjectConfigs = createMapObjectConfigs;
            _createAIConfigs = createAIConfigs;
            _forestAIObjects = new List<int>(_createAIConfigs[MapVertexType.Forest].Count);
            _marshAIObjects = new List<int>(_createAIConfigs[MapVertexType.Marsh].Count);
            _forestMapObjects = new List<int>(_createMapObjectConfigs[MapVertexType.Forest].Count);
            _marshMapObjects = new List<int>(_createMapObjectConfigs[MapVertexType.Marsh].Count);
            
            CreateMapTexture().Forget();
        }

        #region 地图块
        private async UniTaskVoid CreateMapTexture()
        {
            for (var i = 0; i < _mapTexture.Length; i++)
                _mapTexture[i] = await this.MoonGameObjGetPool($"Map/CellTexture_{i}") as Texture2D;
        }

        public void CreateMapData()
        {
            //生成噪声图
            var noiseMap = CreateNoiseMap(_mapInitData.mapSize * _mapConfig.mapBlockSize, _mapInitData.mapSize * _mapConfig.mapBlockSize, _mapConfig.noiseLacunarity);
            //应用地形种子
            Random.InitState(_mapInitData.mapSeed);
            _mapGrid = new MapGrid(_mapInitData.mapSize * _mapConfig.mapBlockSize, _mapInitData.mapSize * _mapConfig.mapBlockSize, _mapConfig.cellSize);

            //确定网格 格子贴图索引
            _mapGrid.CalculateMapVertexType(noiseMap, _mapInitData.marshLimit);

            //初始化网格默认材质
            _mapConfig.mapMaterial.mainTexture = _mapConfig.forestTexutre;
            _mapConfig.mapMaterial.SetTextureScale(MainTex, _mapConfig.cellSize * _mapConfig.mapBlockSize * Vector2.one);

            // 实例化一个沼泽材质
            _marshMaterial = new Material(_mapConfig.mapMaterial);
            _marshMaterial.SetTextureScale(MainTex, Vector2.one);

            //使用随机种子来生成物品
            Random.InitState(_mapInitData.spawnSeed);
            
            CalConfigID();
        }

        /// <summary>
        ///  生成地图块
        /// </summary>
        public BaseMapBlock CreateMapBlock(Vector2Int blockIndex,MapBlockData mapBlockData, Transform parent, Action callbackForMapTexture)
        {
            // 生成地图块物体
            GameObject mapBlockObj = new("Block_" + blockIndex);
            var mapBlock = mapBlockObj.AddComponent<BaseMapBlock>();
            if (!_blockMesh)
                _blockMesh = CreateMesh(_mapConfig.mapBlockSize, _mapConfig.mapBlockSize, _mapConfig.cellSize);

            //生成Mesh
            mapBlockObj.AddComponent<MeshFilter>().mesh = _blockMesh;
            
            CreateMapTexture(blockIndex, (tex, isAllForest) =>
            {
                // 如果完全是森林，没必要在实例化一个材质球
                if (isAllForest)
                {
                    mapBlockObj.AddComponent<MeshRenderer>().sharedMaterial = _mapConfig.mapMaterial;
                }
                else
                {
                    _ = tex;
                    Material material = new(_marshMaterial)
                    {
                        mainTexture = tex
                    };
                    mapBlockObj.AddComponent<MeshRenderer>().material = material;
                }

                callbackForMapTexture?.Invoke();
                // 确定坐标
                var position = _mapConfig.mapBlockSize * _mapConfig.cellSize *
                               (Vector3.right * blockIndex.x + Vector3.forward * blockIndex.y);
                mapBlock.transform.position = position;
                mapBlockObj.transform.SetParent(parent);

                //确定场景配置
                if (mapBlockData == null)
                {
                    mapBlockData = CreateMapObjectData(blockIndex);
                    //生成后进行持久化保存
                    ArchiveManager.Instance.SavaBlockData(blockIndex, mapBlockData);
                }
                else
                {
                    //恢复VertexList
                    RecoverMapBlockData(blockIndex,mapBlockData);
                }
                
                //初始化地图块
                mapBlock.Init(position + _mapConfig.mapBlockSize * _mapConfig.cellSize / 2 * (Vector3.right + Vector3.forward),
                    isAllForest,blockIndex, mapBlockData);
            });

            return mapBlock;
        }
        
        /// <summary>
        ///     生成地形渲染器Mesh
        /// </summary>
        /// <param name="mapHeight"></param>
        /// <param name="mapWidth"></param>
        /// <returns></returns>
        private Mesh CreateMesh(int mapHeight, int mapWidth, float cellSize)
        {
            Mesh mesh = new()
            {
                //确定顶点在哪
                vertices = new[]
                {
                    Vector3.zero,
                    cellSize * mapHeight * Vector3.forward,
                    cellSize * (Vector3.forward * mapHeight + Vector3.right * mapWidth),
                    cellSize * mapWidth * Vector3.right
                },

                //确定那些点构成三角形
                triangles = new[]
                {
                    0, 1, 2,
                    0, 2, 3
                },

                uv = new[]
                {
                    Vector2.zero,
                    Vector2.up,
                    Vector2.one,
                    Vector2.right
                }
            };

            //法线信息
            mesh.RecalculateNormals();
            return mesh;
        }

        /// <summary>
        ///     生成噪音图(基于柏林噪音)
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="factor"></param>
        /// <returns></returns>
        private float[,] CreateNoiseMap(int width, int height, float factor)
        {
            factor += 0.1f;
            //顶点噪音图
            var noiseMap = new float[width, height];

            var offsetX = Random.Range(-1E5f, 1E5f);
            var offsetY = Random.Range(-1E5f, 1E5f);

            for (var x = 0; x < width; x++)
            for (var y = 0; y < height; y++)
                noiseMap[x, y] = Mathf.PerlinNoise(x * factor + offsetX, y * factor + offsetY);

            return noiseMap;
        }

        /// <summary>
        ///    生成地形贴图
        /// </summary>
        private void CreateMapTexture(Vector2Int chunkIndex, Action<Texture2D, bool> callback)
        {
            var isAllForest = true;
            var cellOffsetX = chunkIndex.x * _mapConfig.mapBlockSize + 1;
            var cellOffsetY = chunkIndex.y * _mapConfig.mapBlockSize + 1;

            // 检查是否只有森林类型的格子
            for (var y = 0; y < _mapConfig.mapBlockSize; y++)
            {
                if (!isAllForest) break;
                for (var x = 0; x < _mapConfig.mapBlockSize; x++)
                {
                    var cell = _mapGrid.GetCell(x + cellOffsetX, y + cellOffsetY);
                    if (cell != null && cell.textureIndex != 0)
                    {
                        isAllForest = false;
                        break;
                    }
                }
            }

            Texture2D mapTexture = null;
            if (!isAllForest)
            {
                var textureCellSize = _mapConfig.forestTexutre.width; // 单元格纹理大小（假设所有单元格纹理大小一致）
                var textureSize = _mapConfig.mapBlockSize * textureCellSize; // 大纹理的尺寸
                // 创建目标大纹理（注意：TextureFormat 与源纹理一致）
                mapTexture = new Texture2D(textureSize, textureSize, TextureFormat.DXT1, false);

                // 遍历每个格子，将预制好的单元格纹理“复制”到大纹理的对应位置
                for (var y = 0; y < _mapConfig.mapBlockSize; y++)
                for (var x = 0; x < _mapConfig.mapBlockSize; x++)
                {
                    var textureIndex = _mapGrid.GetCell(x + cellOffsetX, y + cellOffsetY).textureIndex - 1;

                    var cellTexture = textureIndex < 0 || textureIndex >= this._mapTexture.Length
                        ? this._mapTexture[0] // 默认森林纹理
                        : this._mapTexture[textureIndex + 1];

                    // 计算目标位置
                    var targetX = x * textureCellSize;
                    var targetY = y * textureCellSize;

                    // 复制整块纹理到目标纹理
                    Graphics.CopyTexture(cellTexture, 0, 0, 0, 0, textureCellSize, textureCellSize, mapTexture, 0, 0,
                        targetX, targetY);
                }
            }

            callback?.Invoke(mapTexture, isAllForest);
        }
        #endregion

        #region 地图对象
        private void CalConfigID()
        {
            _forestMapObjects.Add(ConfigManager.Instance
                .GetConfig<MapObjectConfig>(ConfigName.MapObject, _createMapObjectConfigs[MapVertexType.Forest][0]).Probability);
            _marshMapObjects.Add(ConfigManager.Instance
                .GetConfig<MapObjectConfig>(ConfigName.MapObject, _createMapObjectConfigs[MapVertexType.Marsh][0]).Probability);

            _marshAIObjects.Add(ConfigManager.Instance
                .GetConfig<AIConfig>(ConfigName.AI, _createAIConfigs[MapVertexType.Forest][0]).Probability);
            _forestAIObjects.Add(ConfigManager.Instance
                .GetConfig<AIConfig>(ConfigName.AI, _createAIConfigs[MapVertexType.Marsh][0]).Probability);
            
            int probability;
            for (var i = 1; i < Math.Max(Math.Max(_forestMapObjects.Capacity, _marshMapObjects.Capacity), Math.Max(_forestAIObjects.Capacity, _marshAIObjects.Capacity)); i++)
            {
                if (i < _forestMapObjects.Capacity)
                {
                    probability = ConfigManager.Instance
                        .GetConfig<MapObjectConfig>(ConfigName.MapObject, _createMapObjectConfigs[MapVertexType.Forest][i]).Probability;
                    _forestMapObjects.Add(_forestMapObjects[i - 1] + Math.Max(probability, 0));
                }

                if (i < _marshMapObjects.Capacity)
                {
                    probability = ConfigManager.Instance
                        .GetConfig<MapObjectConfig>(ConfigName.MapObject, _createMapObjectConfigs[MapVertexType.Marsh][i]).Probability;
                    _marshMapObjects.Add(_marshMapObjects[i - 1] + Math.Max(probability, 0));
                }

                if (i < _marshAIObjects.Capacity)
                {
                    probability = ConfigManager.Instance
                        .GetConfig<AIConfig>(ConfigName.AI, _createAIConfigs[MapVertexType.Marsh][i]).Probability;
                    _marshAIObjects.Add(_marshAIObjects[i - 1] + Math.Max(probability, 0));
                }

                if (i < _forestAIObjects.Capacity)
                {
                    probability = ConfigManager.Instance
                        .GetConfig<AIConfig>(ConfigName.AI, _createAIConfigs[MapVertexType.Forest][i]).Probability;
                    _forestAIObjects.Add(_forestAIObjects[i - 1] + Math.Max(probability, 0));
                }
            }
            
            _forestAIWeightTotal = _forestAIObjects[^1];
            _marshAIWeightTotal = _marshAIObjects[^1];
            _forestMapObjectWeightTotal = _forestMapObjects[^1];
            _marshMapObjectWeightTotal = _marshMapObjects[^1];
        }
        
        private int Lower_Bound(in List<int> t, int value)
        {
            int l = 0, r = t.Count -1;
            while (l < r)
            {
                int mid = (l + r) >>1;
                if (t[mid] < value)
                    l = mid + 1;
                else
                    r = mid;
            }
            return l;
        }

        /// <summary>
        /// 通过权重获取一个地图对象配置ID
        /// </summary>
        private int GetMapObjectConfigIDForWeight(MapVertexType mapVertexType)
        {
            var total = mapVertexType == MapVertexType.Forest
                ? _forestMapObjectWeightTotal
                : _marshMapObjectWeightTotal;
            var randValue = Random.Range(1, total + 1);
            int value = mapVertexType == MapVertexType.Forest ? Lower_Bound(in _forestMapObjects, randValue) : Lower_Bound(in _marshMapObjects, randValue);
            return _createMapObjectConfigs[mapVertexType][value];
        }
        
        /// <summary>
        /// 通过权重获取一个地图对象配置ID
        /// </summary>
        private int GetAIConfigIDForWeight(MapVertexType mapVertexType)
        {
            var total = mapVertexType == MapVertexType.Forest
                ? _forestAIWeightTotal
                : _marshAIWeightTotal;
            int randValue = Random.Range(1, total + 1);
            int index = mapVertexType == MapVertexType.Forest ? Lower_Bound(in _forestAIObjects, randValue) : Lower_Bound(in _marshAIObjects, randValue);
            return _createAIConfigs[mapVertexType][index];
        }
        
        /// <summary>
        /// 生成地图对象数据
        /// </summary>
        private MapBlockData CreateMapObjectData(Vector2Int blockIndex)
        {
            Random.InitState(_mapInitData.spawnSeed);
            MapBlockData mapBlockData = new()
            {
                MapBlockMapObjects = new(),
                MapBlockAIObjects = new(),
                MarshMapVertices =  new List<MapVertex>(_mapConfig.mapBlockSize * _mapConfig.mapBlockSize),
                ForestMapVertices = new List<MapVertex>(_mapConfig.mapBlockSize * _mapConfig.mapBlockSize)
            };

            var offsetX = blockIndex.x * _mapConfig.mapBlockSize;
            var offsetY = blockIndex.y * _mapConfig.mapBlockSize;

            //生成地图对象
            for (var x = 1; x < _mapConfig.mapBlockSize; x++)
            for (var y = 1; y < _mapConfig.mapBlockSize; y++)
            {
                var mapVertex = _mapGrid.GetVertex(x + offsetX, y + offsetY);

                switch (mapVertex.vertexType)
                {
                    case MapVertexType.Forest:
                        mapBlockData.ForestMapVertices.Add(mapVertex);
                        break;
                    case MapVertexType.Marsh:
                        mapBlockData.MarshMapVertices.Add(mapVertex);
                        break;
                }
                
                var configID = GetMapObjectConfigIDForWeight(mapVertex.vertexType);
                var objectConfig =
                    ConfigManager.Instance.GetConfig<MapObjectConfig>(ConfigName.MapObject, configID);

                if (objectConfig.isEmpty) continue;
                var pos = mapVertex.position + new Vector3(Random.Range(-_mapConfig.cellSize / 2, _mapConfig.cellSize / 2), 0f,
                    Random.Range(-_mapConfig.cellSize / 2, _mapConfig.cellSize / 2));
                mapVertex.MapObjectID = _mapData.CurID;
                mapBlockData.MapBlockMapObjects.Add(_mapData.CurID , CreateMapObjectData(configID, pos, objectConfig.DestroyDays));
            }

            List<MapObjectData> aiDataList = CreateAIObjectDataRefresh(mapBlockData);
            foreach (var aiData in aiDataList)
            {
                mapBlockData.MapBlockAIObjects.Add(aiData.ID, aiData);
            }

            return mapBlockData;
        }

        /// <summary>
        /// 恢复地图块数据
        /// 目前只恢复了VertexList
        /// </summary>
        private void RecoverMapBlockData(Vector2Int blockIndex, MapBlockData mapBlockData)
        {
            mapBlockData.ForestMapVertices = new(_mapConfig.mapBlockSize * _mapConfig.mapBlockSize);
            mapBlockData.MarshMapVertices = new(_mapConfig.mapBlockSize * _mapConfig.mapBlockSize);
            var offsetX = blockIndex.x * _mapConfig.mapBlockSize;
            var offsetY = blockIndex.y * _mapConfig.mapBlockSize;

            //生成地图对象
            for (var x = 1; x < _mapConfig.mapBlockSize; x++)
            for (var y = 1; y < _mapConfig.mapBlockSize; y++)
            {
                var mapVertex = _mapGrid.GetVertex(x + offsetX, y + offsetY);
                switch (mapVertex.vertexType)
                {
                    case MapVertexType.Forest:
                        mapBlockData.ForestMapVertices.Add(mapVertex);
                        break;
                    case MapVertexType.Marsh:
                        mapBlockData.MarshMapVertices.Add(mapVertex);
                        break;
                } 
            }
        }

        /// <summary>
        /// 生成一个地图对象的数据
        /// </summary>
        public MapObjectData CreateMapObjectData(int mapObjectConfigID,Vector3 pos)
        {
            MapObjectData mapObjectData = null;
            MapObjectConfig mapObjectConfig = ConfigManager.Instance.GetConfig<MapObjectConfig>(ConfigName.MapObject, mapObjectConfigID);
            if (!mapObjectConfig.isEmpty)
            {
                mapObjectData = CreateMapObjectData(mapObjectConfigID, pos, mapObjectConfig.DestroyDays);
            }
            return mapObjectData;
        }

        private readonly List<MapObjectData> _mapObjectDataList = new();
        /// <summary>
        /// 为地图块刷新，生成地图对象列表
        /// 可能为null
        /// 通过一块地图块Index索引，返回一个今天这块地图块多出来的物品数据
        /// </summary>
        public List<MapObjectData> CreateMapObjectDataRefresh(Vector2Int blockIndex)
        {
            //清理数据
            _mapObjectDataList.Clear();
            var offsetX = blockIndex.x * _mapConfig.mapBlockSize;
            var offsetY = blockIndex.y * _mapConfig.mapBlockSize;
            
            //遍历地图顶点
            for (var x = 1; x < _mapConfig.mapBlockSize; x++)
            for (var y = 1; y < _mapConfig.mapBlockSize; y++)
            {
                //如果刷新概率未命中，则这个顶点不刷新
                if (Random.Range(0, _mapConfig.RefreshProbaility) != 0) continue;
                
                var mapVertex = _mapGrid.GetVertex(x + offsetX, y + offsetY);
                //不为空则不能生成
                if(mapVertex.MapObjectID != 0) continue;
                
                var configID = GetMapObjectConfigIDForWeight(mapVertex.vertexType);
                var objectConfig =
                    ConfigManager.Instance.GetConfig<MapObjectConfig>(ConfigName.MapObject, configID);

                if (!objectConfig.isEmpty)
                {
                    var pos = mapVertex.position + new Vector3(Random.Range(-_mapConfig.cellSize / 2, _mapConfig.cellSize / 2), 0f,
                        Random.Range(-_mapConfig.cellSize / 2, _mapConfig.cellSize / 2));
                    mapVertex.MapObjectID = _mapData.CurID;
                    _mapObjectDataList.Add(CreateMapObjectData(configID, pos, objectConfig.DestroyDays));
                }
            }
            return _mapObjectDataList;
        }

        /// <summary>
        /// 为地图块刷新，生成AI对象列表
        /// </summary>
        public List<MapObjectData> CreateAIObjectDataRefresh(MapBlockData mapBlockData)
        {
            _mapObjectDataList.Clear();

            //最多要生成的数量
            int maxCount = _mapConfig.MaxAIOnBlock - mapBlockData.MapBlockAIObjects.Count;
            
            //生成AI数据
            //一块地图块，森林或沼泽的定点数要大于配置的才生成AI
            if (mapBlockData.ForestMapVertices.Count > _mapConfig.MinVertexCountForAI)
            {
                for (int i = 0; i < maxCount; i++)
                {
                    int configID = GetAIConfigIDForWeight(MapVertexType.Forest);
                    AIConfig config = ConfigManager.Instance.GetConfig<AIConfig>(ConfigName.AI, configID);
                    if(!config.isEmpty) _mapObjectDataList.Add(CreateMapObjectData(configID, Vector3.zero, -1));
                }
            }
            if (mapBlockData.MarshMapVertices.Count > _mapConfig.MinVertexCountForAI)
            {
                for (int i = 0; i < maxCount; i++)
                {
                    int configID = GetAIConfigIDForWeight(MapVertexType.Marsh);
                    AIConfig config = ConfigManager.Instance.GetConfig<AIConfig>(ConfigName.AI, configID);
                    if(!config.isEmpty) _mapObjectDataList.Add(CreateMapObjectData(configID, Vector3.zero, -1));
                }
            }
            return _mapObjectDataList;
        }

        private MapObjectData CreateMapObjectData(int mapObjectConfigID, Vector3 position, int destroyDays)
        {
            return MapObjectData.CreateMapObjectData(_mapData.CurID++, mapObjectConfigID, destroyDays, position);
        }
        #endregion
    }
}